﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JXT.PrimaryKey.Batman.Collections;
using JXT.PrimaryKey.Batman.Domain.Specifications;
using JXT.PrimaryKey.Batman.Domain.Quotation.Models;
using JXT.PrimaryKey.Batman.Domain.Services;
using JXT.PrimaryKey.Batman.Domain.Quotation.Services;
using JXT.PrimaryKey.Batman.Domain.Quotation.Repositories;

namespace JXT.PrimaryKey.Batman.Domain.Quotation.Services.Default
{
    public class RealTimeQuoteService : CachedServiceBase<RealTimeQuote>, IRealTimeQuoteService
    {
        private static readonly string _marketStatusCacheKey = String.Format("{0}_marketstatus", CacheSpace);

        private static readonly TimeSpan _cacheTimeSpan = TimeSpan.FromDays(7);

        public void Add(RealTimeQuote entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            LoadRepository<IRealTimeQuoteRepository>().Add(entity);
            //Cache.Add(buildCacheKey(entity.Code, entity.MarketType), entity, _cacheTimeSpan);
        }

        public void Add(IEnumerable<RealTimeQuote> list)
        {
            if (list == null)
                throw new ArgumentNullException("list");
            LoadRepository<IRealTimeQuoteRepository>().Add(list);
            //foreach (var item in list)
            //{
            //    Cache.Add(buildCacheKey(item.Code, item.MarketType), item, _cacheTimeSpan);
            //}
        }

        public void AddCache(RealTimeQuote entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            Cache.Add(buildCacheKey(entity.Code, entity.MarketType), entity, _cacheTimeSpan);
        }

        public void AddRank(IEnumerable<RealTimeQuote> source, MarketType marketType, SecuritiesType securitiesType, MarketRankType rankType)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            var key = buildRankCacheKey(marketType, securitiesType, rankType);
            Cache.Add(key, source.ToList(), _cacheTimeSpan);
        }

        public RealTimeQuote GetSingle(string code, MarketType type = MarketType.Unknown)
        {
            if (type == MarketType.Unknown)
                type = getMarketType(code);
            string key = buildCacheKey(code, type);
            RealTimeQuote result = Cache.Get(key) as RealTimeQuote;
            if (result == null)
            {
                result = LoadRepository<IRealTimeQuoteRepository>().GetSingle(code, type);
                //if (result != null)
                //    Cache.Add(key, result);
            }
            return result;
        }

        public IEnumerable<RealTimeQuote> GetRankList(MarketType marketType, SecuritiesType securitiesType, MarketRankType rankType, int num = 5)
        {
            var key = buildRankCacheKey(marketType, securitiesType, rankType);
            IList<RealTimeQuote> list = Cache.Get(key) as IList<RealTimeQuote>;
            if (list == null)
                return new List<RealTimeQuote>();
            return list.Take(num).ToList();
        }

        public IEnumerable<RealTimeQuote> GetList(string code, MarketType type = MarketType.Unknown, DateTime? startTime = null, DateTime? endTime = null)
        {
            if (type == MarketType.Unknown)
                type = getMarketType(code);
            return LoadRepository<IRealTimeQuoteRepository>().GetList(code, type, startTime, endTime);
        }

        private string buildCacheKey(string code, MarketType type)
        {
            return String.Format("{0}_{1}_{2}", CacheSpace, type, code);
        }

        private MarketType getMarketType(string code)
        {
            var stock = LoadService<ISecuritiesService>().GetSingle(code);
            if (stock != null)
                return stock.MarketType;
            else
                return MarketType.Unknown;
        }

        private bool isDuplicateCode(RealTimeQuote entity)
        {
            if (entity.MarketType == MarketType.Shanghai)
            {
                int codeInt32;
                if (Int32.TryParse(entity.Code, out codeInt32))
                {
                    if ((codeInt32 >= 1 && codeInt32 <= 17) || (codeInt32 >= 910 && codeInt32 <= 917))
                        return true;
                }
            }
            return false;
        }

        private string buildRankCacheKey(MarketType marketType, SecuritiesType securitiesType, MarketRankType rankType)
        {
            return String.Format("{0}_rank_{1}_{2}_{3}", CacheSpace, marketType, securitiesType, rankType);
        }

        public void SetMarketStatus(IEnumerable<MarketStatus> status)
        {
            if (status == null)
                throw new ArgumentNullException("status");
            Cache.Add(_marketStatusCacheKey, status.ToList(), _cacheTimeSpan);
        }

        public IEnumerable<MarketStatus> GetMarketStatus()
        {
            var find = Cache.Get(_marketStatusCacheKey) as IEnumerable<MarketStatus>;
            if (find == null)
                find = new List<MarketStatus>();
            return find;
        }


        public void AddLastData(MarketType type, DateTime? dt, TimeSortType timesort = TimeSortType.Daily)
        {
            if (type == MarketType.Unknown)
                throw new ArgumentNullException("markettype is can not unknown");
            if (dt == null)
                dt = DateTime.Now;
            if (LoadRepository<IRealTimeQuoteRepository>().Count(type, dt.Value) > 0)
                return;
            var list = LoadRepository<ISecuritiesRepository>().GetList(type);
            foreach (var item in list)
            {
                string key = buildCacheKey(item.Code, item.MarketType);
                RealTimeQuote result = Cache.Get(key) as RealTimeQuote;
                if (null == result)
                    continue;
                if (result.UpdateTime.Date != dt.Value.Date)
                    continue;
                result.UpdateTime = result.UpdateTime.Date;
                Add(result);
            }
        }
    }
}
